/**
 * 版权所有(C)，上海勾芒信息科技，2017，所有权利保留。
 * 
 * 项目名：	cards-web
 * 文件名：	WxComponentAuthorServiceImpl.java
 * 模块说明：	
 * 修改历史：
 * 2017年5月23日 - Debenson - 创建。
 */
package me.chanjar.weixin.component.api.impl;

import java.util.Map;
import java.util.concurrent.locks.Lock;

import com.alex.wechat.component.config.WxComponentContext;
import com.gomore.jeecg.common.Assert;
import com.google.common.collect.Maps;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.JsonMapper;
import me.chanjar.weixin.common.util.URL;
import me.chanjar.weixin.component.api.WxCompAuthorService;
import me.chanjar.weixin.component.api.WxCompConfigStorage;
import me.chanjar.weixin.component.api.WxCompService;
import me.chanjar.weixin.component.bean.author.WxApiQueryAuthResult;
import me.chanjar.weixin.component.bean.author.WxAuthorizerAccessToken;
import me.chanjar.weixin.component.bean.author.WxAuthorizerOption;
import me.chanjar.weixin.component.bean.author.WxGetAuthorizerInfoResult;
import me.chanjar.weixin.component.bean.author.WxPreauthorCode;

/**
 * @author Debenson
 * @since 0.1
 */
public class WxCompAuthorServiceImpl implements WxCompAuthorService {
  private static final String BASE_URL = "https://api.weixin.qq.com/cgi-bin/component";

  private final WxCompService wxCompService;

  public WxCompAuthorServiceImpl(WxCompService wxCompService) {
    this.wxCompService = wxCompService;
  }

  @Override
  public String getPreauthorCode() throws WxErrorException {
    return getPreauthorCode(false);
  }

  @Override
  public String getPreauthorCode(boolean forceRefresh) throws WxErrorException {
    Lock lock = getConfig().getPreauthorCodeLock();
    try {
      lock.lock();

      if (forceRefresh) {
        getConfig().expirePreauthorCode();
      }

      if (getConfig().isPreauthorCodeExpired()) {
        WxPreauthorCode preauthorCode = retrievePreauthorCode();
        getConfig().updatePreauthorCode(preauthorCode);
      }
    } finally {
      lock.unlock();
    }
    return getConfig().getPreauthorizationCode();
  }

  @Override
  public String getComponentLoginPageUrl() throws WxErrorException {
    URL urlMapper = new URL("https://mp.weixin.qq.com/cgi-bin/componentloginpage");
    urlMapper.addParameter("component_appid", WxComponentContext.getAppId());
    urlMapper.addParameter("pre_auth_code", getPreauthorCode());
    urlMapper.addParameter("redirect_uri", getConfig().getAuthorizationCallbackUrl());
    return urlMapper.toString();
  }

  private WxPreauthorCode retrievePreauthorCode() throws WxErrorException {
    WxCompConfigStorage config = getConfig();
    Map<String, Object> params = Maps.newHashMap();
    params.put("component_appid", config.getAppId());

    String url = BASE_URL + "/api_create_preauthcode";
    final String postData = JsonMapper.defaultMapper().toJson(params);
    String response = wxCompService.httpPost(url, postData);
    return JsonMapper.defaultMapper().fromJson(response, WxPreauthorCode.class);
  }

  @Override
  public WxApiQueryAuthResult queryAuthor(String authorizationCode) throws WxErrorException {
    Assert.assertArgumentNotEmpty(authorizationCode, "authorizationCode");

    WxCompConfigStorage config = getConfig();
    Map<String, Object> params = Maps.newHashMap();
    params.put("component_appid", config.getAppId());
    params.put("authorization_code", authorizationCode);

    String url = BASE_URL + "/api_query_auth";
    String response = wxCompService.httpPost(url, JsonMapper.defaultMapper().toJson(params));
    return JsonMapper.defaultMapper().fromJson(response, WxApiQueryAuthResult.class);
  }

  @Override
  public WxAuthorizerAccessToken getAuthorizerAccessToken(String authorizerAppId,
      String authorizerRefreshToken) throws WxErrorException {
    Assert.assertArgumentNotEmpty(authorizerAppId, "authorizerAppId");
    Assert.assertArgumentNotEmpty(authorizerRefreshToken, "authorizerRefreshToken");

    WxCompConfigStorage config = getConfig();
    Map<String, Object> params = Maps.newHashMap();
    params.put("component_appid", config.getAppId());
    params.put("authorizer_appid", authorizerAppId);
    params.put("authorizer_refresh_token", authorizerRefreshToken);

    String url = BASE_URL + "/api_authorizer_token";
    String response = wxCompService.httpPost(url, JsonMapper.defaultMapper().toJson(params));
    return JsonMapper.defaultMapper().fromJson(response, WxAuthorizerAccessToken.class);
  }

  @Override
  public WxGetAuthorizerInfoResult getAuthorizerInfo(String authorizerAppId)
      throws WxErrorException {
    Assert.assertArgumentNotEmpty(authorizerAppId, "authorizerAppId");

    WxCompConfigStorage config = getConfig();
    Map<String, Object> params = Maps.newHashMap();
    params.put("component_appid", config.getAppId());
    params.put("authorizer_appid", authorizerAppId);

    String url = BASE_URL + "/api_get_authorizer_info";
    String response = wxCompService.httpPost(url, JsonMapper.defaultMapper().toJson(params));
    return JsonMapper.defaultMapper().fromJson(response, WxGetAuthorizerInfoResult.class);
  }

  @Override
  public WxAuthorizerOption getAuthorizerOption(String authorizerAppId, String optionName)
      throws WxErrorException {
    Assert.assertArgumentNotEmpty(authorizerAppId, "authorizerAppId");
    Assert.assertArgumentNotEmpty(optionName, "optionName");

    WxCompConfigStorage config = getConfig();
    Map<String, Object> params = Maps.newHashMap();
    params.put("component_appid", config.getAppId());
    params.put("authorizer_appid", authorizerAppId);
    params.put("option_name", optionName);

    String url = BASE_URL + "/api_get_authorizer_option";
    String response = wxCompService.httpPost(url, JsonMapper.defaultMapper().toJson(params));
    return JsonMapper.defaultMapper().fromJson(response, WxAuthorizerOption.class);
  }

  @Override
  public void setAuthorizerOption(String authorizerAppId, String optionName, String optionValue)
      throws WxErrorException {
    Assert.assertArgumentNotEmpty(authorizerAppId, "authorizerAppId");
    Assert.assertArgumentNotEmpty(optionName, "optionName");

    WxCompConfigStorage config = getConfig();
    Map<String, Object> params = Maps.newHashMap();
    params.put("component_appid", config.getAppId());
    params.put("authorizer_appid", authorizerAppId);
    params.put("option_name", optionName);
    params.put("option_name", optionName);

    String url = BASE_URL + "/api_set_authorizer_option";
    wxCompService.httpPost(url, JsonMapper.defaultMapper().toJson(params));
  }

  private WxCompConfigStorage getConfig() {
    return wxCompService.getConfigStorage();
  }

}
